﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Vk.Methods.Common;

#endregion

namespace Vk.Methods.Docs
{
    /// <summary>
    ///     Документы
    /// </summary>
    public class Docs
    {
        private readonly Api _api;

        public Docs(Api api)
        {
            _api = api;
        }

        /// <summary>
        ///     Копирует документ в документы текущего пользователя
        /// </summary>
        /// <param name="docId">Идентификатор документа</param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества, которому принадлежит документ</param>
        /// <param name="accessKey">
        ///     Ключ доступа документа. Этот параметр следует передать, если вместе с остальными данными о
        ///     документе было возвращено поле access_key.
        /// </param>
        /// <returns>После успешного выполнения возвращает идентификатор созданного документа</returns>
        public async Task<int> Add(int docId, int ownerId, string accessKey = null)
        {
            var query = new ApiQuery("docs.add")
                .Add("doc_id", docId)
                .Add("owner_id", ownerId)
                .Add("access_key", accessKey);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Int().HasValue ? result.Int().Value : -1;
        }

        /// <summary>
        ///     Удаляет документ пользователя или группы.
        /// </summary>
        /// <param name="docId">ID документа.</param>
        /// <param name="ownerId">
        ///     ID владельца документы. Если удаляемый документ находится на странице группы, в этом параметре
        ///     должно стоять значение, равное -id группы.
        /// </param>
        /// <returns>При успешном удалении документа сервер вернет true. </returns>
        public async Task<bool> Delete(int docId, int ownerId)
        {
            var query = new ApiQuery("docs.delete")
                .Add("doc_id", docId)
                .Add("owner_id", ownerId);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Возвращает расширенную информацию о документах текущего пользователя.
        /// </summary>
        /// <param name="ownerId">
        ///     ID пользователя или группы, документы которого нужно вернуть. По умолчанию – id текущего
        ///     пользователя. Если необходимо получить документы группы, в этом параметре должно стоять значение, равное -id
        ///     группы.
        /// </param>
        /// <param name="count">Количество документов, которое нужно вернуть. (по умолчанию – все документы)</param>
        /// <param name="offset">Смещение, необходимое для выборки определенного подмножества документов.</param>
        public async Task<ListCount<Document>> Get(int? ownerId = null, int? count = null, int? offset = null, ApiEnum<DocumentType> type = null)
        {
            var query = new ApiQuery("docs.get")
                .Add("owner_id", ownerId)
                .Add("count", count)
                .Add("offset", offset);

            var result = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                var nodes = result.SelectNodes("items/*");
                if (nodes != null && nodes.Any())
                    return new ListCount<Document>(result.Int("count").Value,
                                                   nodes.Select(x => new Document(x)).ToList());
            }
            return null;
        }

        /// <summary>
        ///     Возвращает информацию о документах.
        /// </summary>
        /// <param name="docs">
        ///     Перечисленные через запятую идентификаторы – идущие через знак подчеркивания id пользователей,
        ///     которым принадлежат документы, и id самих документов.
        /// </param>
        public async Task<List<Document>> GetById(IEnumerable<string> docs)
        {
            var query = new ApiQuery("docs.getById")
                .Add("docs", docs);

            var result = await _api.Manager.Execute(query);

            if (!_api.Manager.MethodSuccessed)
                return null;

            var nodes = result.SelectNodes("doc");
            return (from ApiNode node in nodes select new Document(node)).ToList();
        }

        /// <summary>
        ///     Возвращает адрес сервера для загрузки документов.
        /// </summary>
        /// <param name="groupId">
        ///     Идентификатор сообщества (если необходимо загрузить документ в список документов сообщества).
        ///     Если документ размещается на стене группы, этот параметр указывать не нужно.
        /// </param>
        public async Task<string> GetUploadServer(int? groupId = null)
        {
            var query = new ApiQuery("docs.getUploadServer")
                .Add("group_id", groupId);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed ? result.String("upload_url") : "";
        }

        /// <summary>
        ///     Возвращает адрес сервера для загрузки документов в папку отправленные, для последующей отправки документа на стену
        ///     или личным сообщением.
        /// </summary>
        /// <param name="groupId">Идентификатор сообщества, в которое нужно загрузить документ</param>
        public async Task<string> GetWallUploadServer(int? groupId = null)
        {
            var query = new ApiQuery("docs.getWallUploadServer")
                .Add("group_id", groupId);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed ? result.String("upload_url") : null;
        }

        /// <summary>
        ///     Сохраняет документ после его успешной загрузки на сервер.
        /// </summary>
        /// <param name="file">Параметр, возвращаемый в результате загрузки файла на сервер.</param>
        /// <param name="title">Название документа</param>
        /// <param name="tags">Метки для поиска</param>
        public async Task<Document> Save(string file, string title = null, string tags = null)
        {
            var query = new ApiQuery("docs.save")
                .Add("file", file)
                .Add("title", title)
                .Add("tags", tags);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed ? new Document(result) : null;
        }
    }
}